package org.biubiu0002.baiblog.im.handler;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.biubiu0002.baiblog.im.constants.MessageConstants;
import org.biubiu0002.baiblog.im.constants.HeartbeatConstants;
import org.biubiu0002.baiblog.im.dto.message.Message;
import org.biubiu0002.baiblog.im.session.ServerSession;
import org.biubiu0002.baiblog.im.utils.Serializer;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @Author: biubiu0002
 * @Date: 2022/9/2 11:35
 **/
@Component
@Slf4j
@ChannelHandler.Sharable
public class WebSocketHandShakeHandler extends ChannelInboundHandlerAdapter {

    @Resource
    private HeartbeatHandler heartbeatHandler;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(!(msg instanceof WebSocketFrame)){
            super.channelRead(ctx, msg);
            return;
        }
        if(msg instanceof TextWebSocketFrame){
            TextWebSocketFrame frame = (TextWebSocketFrame) msg;
            String text = frame.text();
            //心跳处理
            if(handlePingPong(text,ctx)){
                super.channelRead(ctx,msg);
                return;
            }

            try {
                Message message = Serializer.parseMessage(text, ctx);
                super.channelRead(ctx,message);
            }catch (Exception e){
                log.error("序列化失败:",e);
            }
        }

    }

    public boolean handlePingPong(String text,ChannelHandlerContext ctx){
        if(MessageConstants.PING.equals(text)){
//            log.info("收到ping，发送pong");
            TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(MessageConstants.PONG);
            ctx.writeAndFlush(textWebSocketFrame);
            return true;
        }
        return false;
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof WebSocketServerProtocolHandler.ServerHandshakeStateEvent){
            //握手成功 去除登录handler
            ChannelPipeline pipeline = ctx.pipeline();
            pipeline.remove("httpAuth");
            log.info("websocket 握手成功");
            log.info("新的 WebSocket 客户端加入，通道为：" + ctx.channel());
            //连接成功的处理
            ServerSession session = ServerSession.getSession(ctx);
            session.bind();
            session.setLogin(true);
            //空闲处理
            pipeline.addAfter("websocketHandShake","IdleStateHandler",new IdleStateHandler(HeartbeatConstants.MAX_READ_IDLE_TIME,0,0, TimeUnit.SECONDS));
            //心跳处理器
            pipeline.addAfter("IdleStateHandler","HeartbeatHandler",heartbeatHandler);
        }
        else{
            super.userEventTriggered(ctx, evt);
        }
    }

    /**
     * 客户端断开连接
     * @param ctx 上下文
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        ServerSession session = ServerSession.getSession(ctx);
        ServerSession.closeSession(session);
        super.channelInactive(ctx);
    }
}
